package com.md.util;

import com.md.model.base.FileStream;
import com.md.model.excel.MergeInfo;
import com.md.model.html.CustomLabel;
import com.md.model.html.TD;
import com.md.model.word.Document;
import com.md.model.word.ParagraphFontStyleInfo;
import com.md.model.word.ParagraphStyleInfo;
import com.md.model.word.TableCellStyleInfo;
import com.md.model.word.TableRowStyleInfo;
import com.md.model.word.TableStyleInfo;
import com.md.model.word.WordColorInfo;
import com.md.model.word.WordParagraph;
import com.md.value.ConvertType;
import com.md.value.MergeType;
import com.md.value.html.FontStyle;
import com.md.value.html.FontWeight;
import com.md.value.html.LabelAttributeType;
import com.md.value.html.LabelStyleType;
import com.md.value.html.TextDecoration;
import com.md.value.html.Unit;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.Borders;
import org.apache.poi.xwpf.usermodel.BreakType;
import org.apache.poi.xwpf.usermodel.IBodyElement;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.UnderlinePatterns;
import org.apache.poi.xwpf.usermodel.VerticalAlign;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFPicture;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFStyles;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDecimalNumber;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSpacing;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyles;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVMerge;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVerticalAlignRun;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STLineSpacingRule;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.impl.CTPImpl;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.impl.CTPPrImpl;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.impl.CTParaRPrImpl;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.impl.CTRImpl;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.impl.CTRPrImpl;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.impl.CTTcImpl;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.impl.CTTcPrImpl;
import org.w3c.dom.Node;

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.md.value.html.HtmlConstants.DEFAULT_TABLE;
import static com.md.value.html.HtmlConstants.TR_START;

/**
 * @author 刘骄阳
 * 2024-05-16 23:44
 */
@Slf4j
public class WordUtil {

  /**
   * 回车符ASCII码
   */
  private static final short ENTER_ASCII = 13;
  /**
   * 空格符ASCII码
   */
  private static final short SPACE_ASCII = 32;
  /**
   * 水平制表符ASCII码
   */
  private static final short TABULATION_ASCII = 9;

  public static String convertToHtml(final XWPFParagraph paragraph, final String label, final ConvertType convertType) {
    ParagraphStyleInfo paragraphStyleInfo = processParagraph(paragraph);
    // 解析样式
    List<CustomLabel> customLabels = buildCustomLabel(label, paragraphStyleInfo, paragraphStyleInfo.getFontStyles());
    return HtmlUtil.generateHTMLCode("p", null, null, customLabels.stream().map(baseLabel ->
        HtmlUtil.generateHTMLCode(label, baseLabel.getStyles(), baseLabel.getAttributes(), baseLabel.getContent()))
      .collect(Collectors.joining()));
  }

  public static String convertToHtml(final XWPFTable xwpfTable, final String label, final ConvertType convertType) {
    StringBuilder htmlContent = new StringBuilder(DEFAULT_TABLE);
    TableStyleInfo tableStyleInfo = processTable(xwpfTable);
    List<TableRowStyleInfo> tableStyleInfoRows = tableStyleInfo.getRows();
    Map<String, MergeInfo> mergeMap = tableStyleInfo.getMergeMap();
    int size = tableStyleInfoRows.size();
    for (int i = 0; i < size; i++) {
      htmlContent.append(TR_START);
      TableRowStyleInfo tableRowStyleInfo = tableStyleInfoRows.get(i);
      List<TableCellStyleInfo> cells = tableRowStyleInfo.getCells();
      for (int j = 0; j < cells.size(); j++) {
        MergeInfo mergeInfo = mergeMap.get(i + "_" + j);
        if (mergeInfo != null && mergeInfo.getType() == MergeType.CONTINUE) {
          continue;
        }
        TableCellStyleInfo tableCellStyleInfo = cells.get(j);
        List<ParagraphStyleInfo> cellFontStyles = tableCellStyleInfo.getCellStyles();
        List<CustomLabel> customLabels = buildCustomLabel(label, cellFontStyles);
        String content = customLabels.stream().map(baseLabel -> HtmlUtil.generateHTMLCode(baseLabel.getLabel(),
          baseLabel.getStyles(), baseLabel.getAttributes(), baseLabel.getContent())).collect(Collectors.joining());
        TD td = buildTD(tableCellStyleInfo, mergeInfo);
        // 获取单元格样式
        htmlContent.append(HtmlUtil.generateHTMLCode(td.getLabel(), td.getStyles(), td.getAttributes(), content));
      }
      htmlContent.append("</tr>");
    }
    htmlContent.append("</table>");
    // 解析样式
    return htmlContent.toString();
  }

  public static TD buildTD(final TableCellStyleInfo cellStyle, final MergeInfo mergeInfo) {
    TD td = new TD();
    Optional.ofNullable(mergeInfo).ifPresent(merge -> {
      if (merge.getMergeRowCount() != 0) {
        td.addAttribute(LabelAttributeType.ROWSPAN, merge.getMergeRowCount());
      }
      if (merge.getMergeCellCount() != 0) {
        td.addAttribute(LabelAttributeType.COLSPAN, merge.getMergeCellCount());
      }
    });
    // 背景色
//    if (cellStyle.getBackgroundColor() != null && cellStyle.getBackgroundColor().getColor() != null) {
//      td.addStyle(LabelStyleType.BACKGROUND_COLOR, "#" + cellStyle.getBackgroundColor().getColor());
//    }
    return td;
  }

  public static List<CustomLabel> buildCustomLabel(final String label,
                                                   final ParagraphStyleInfo paragraphStyleInfo,
                                                   final List<ParagraphFontStyleInfo> paragraphFontStyleInfos) {
    List<CustomLabel> childrenLabels = new ArrayList<>();
    if (paragraphFontStyleInfos.isEmpty()) {
      // 说明没有单独的字体样式,设置整个样式
      CustomLabel customLabel = new CustomLabel(label);
      customLabel.setContent(paragraphStyleInfo.getContent());
      childrenLabels.add(customLabel);
      return childrenLabels;
    }
    paragraphFontStyleInfos.forEach(fontStyle -> {
      CustomLabel customLabel = new CustomLabel(label);
      // 字体大小
      Optional.ofNullable(fontStyle.getFontSize()).ifPresent(fontSize -> {
        customLabel.addStyle(LabelStyleType.FONT_SIZE, fontStyle.getFontSize(), Unit.PX);
      });

      // 字体粗细
      Optional.ofNullable(fontStyle.getIsBold()).filter(isBold -> isBold).ifPresent(isBold ->
        customLabel.addStyle(LabelStyleType.FONT_WEIGHT, FontWeight.BOLD.getValue()));

      // 字体倾斜
      Optional.ofNullable(fontStyle.getIsItalic()).ifPresent(isItalic -> {
        if (isItalic) {
          customLabel.addStyle(LabelStyleType.FONT_STYLE, FontStyle.ITALIC.getValue());
        }
      });

      // 字体颜色
      if (fontStyle.getIsColor()) {
        customLabel.addStyle(LabelStyleType.COLOR, "#" + fontStyle.getColor().getColor());
      }

      // 字体风格
      Optional.ofNullable(fontStyle.getFontName()).ifPresent(fontName ->
        customLabel.addStyle(LabelStyleType.FONT_FAMILY, fontName));
      // 删除线和下划线
      StringBuilder textDecoration = new StringBuilder();
      if (fontStyle.getIsUnderLine()) {
        // 判断单元格或者单元格文字是否有下划线
        textDecoration.append(TextDecoration.UNDERLINE.getCode());
      }
      if (Optional.ofNullable(fontStyle.getIsStrikeOut()).orElse(false)) {
        // 判断单元格或者单元格文字是否有删除线
        textDecoration.append(" ").append(TextDecoration.LINE_THROUGH.getCode());
      }
      if (textDecoration.length() != 0) {
        customLabel.addStyle(LabelStyleType.TEXT_DECORATION, textDecoration.toString());
      }
      customLabel.setContent(fontStyle.getContent());
      childrenLabels.add(customLabel);
    });
    return childrenLabels;
  }

  public static List<CustomLabel> buildCustomLabel(final String label,
                                                   final List<ParagraphStyleInfo> paragraphFontStyleInfos) {
    List<CustomLabel> labels = new ArrayList<>();
    if (paragraphFontStyleInfos.isEmpty()) {
      // 说明没有单独的字体样式,设置整个样式
      CustomLabel customLabel = new CustomLabel(label);
      customLabel.setContent("");
      labels.add(customLabel);
      return labels;
    }
    paragraphFontStyleInfos.forEach(fontStyle -> {
      List<CustomLabel> customLabels = buildCustomLabel(label, fontStyle, fontStyle.getFontStyles());
      String content = customLabels.stream().map(baseLabel -> HtmlUtil.generateHTMLCode(label, baseLabel.getStyles(),
        baseLabel.getAttributes(), baseLabel.getContent())).collect(Collectors.joining());
      CustomLabel customLabel = new CustomLabel("p");
      customLabel.setContent(content);
      if (fontStyle.getParagraphAlignment() != null) {
        customLabel.addStyle(LabelStyleType.TEXT_ALIGN, fontStyle.getVerticalAlign());
      }
      labels.add(customLabel);
    });
    return labels;
  }

  /**
   * 解析段落样式
   *
   * @param paragraph 段落
   * @param styles    整个样式
   */
  private static void processParagraph(final XWPFParagraph paragraph, final XWPFStyles styles) {
    ParagraphStyleInfo paragraphStyleInfo = new ParagraphStyleInfo();
    CTPImpl ctp = (CTPImpl) paragraph.getCTP();
    CTPPrImpl pPr = (CTPPrImpl) ctp.getPPr();
    CTParaRPrImpl rPr = (CTParaRPrImpl) pPr.getRPr();
    // 样式id
    String styleID = paragraph.getStyleID();

    // 对齐方式
    paragraphStyleInfo.setParagraphAlignment(paragraph.getAlignment());

    // 垂直对齐
    paragraphStyleInfo.setVerticalAlignment(paragraph.getVerticalAlignment());

    // 左边距：
    int indentationLeft = paragraph.getIndentationLeft();
    // 右边距：
    int indentationRight = paragraph.getIndentationRight();

    // 首行缩进：
    paragraph.getIndentationFirstLine();
    // 左缩进：
    paragraph.getIndentationLeft();
    // 右缩进：
    paragraph.getIndentationRight();
    // 悬挂缩进：
    paragraph.getIndentationHanging();
    Borders borderTop = paragraph.getBorderTop();


    // 处理每个字的样式
    List<XWPFRun> runs = paragraph.getRuns();
    runs.forEach(xwpfRun -> {
      String text = xwpfRun.getText(-1);
      System.out.println(text);
      // 字体颜色
      String color = xwpfRun.getColor();
      System.out.println(color);

      // 字体
      String fontFamily = xwpfRun.getFontFamily();
      System.out.println(fontFamily);
      String fontName = xwpfRun.getFontName();
      System.out.println(fontName);

      // 字体大小
      int fontSize = xwpfRun.getFontSize();
      System.out.println(fontSize);
      // 下划线
      UnderlinePatterns underline = xwpfRun.getUnderline();
      System.out.println(underline.getValue());

      // 是否加粗
      boolean isBold = xwpfRun.isBold();

      // 是否倾斜
      boolean italic = xwpfRun.isItalic();


      // 是否删除线
      boolean strikeThrough = xwpfRun.isStrikeThrough();
      CTR ctr1 = xwpfRun.getCTR();
      CTRPr ctr = ctr1.getRPr();
      // 阴影
//      List<CTShd> shdList = ctr.getShdList();
//      if (ctr.isSetShd()) {
//        // 获取到的阴影
//        CTShdImpl shd = (CTShdImpl) ctr.getShd();
//        // 获取阴影类型
//        String val = shd.getVal().toString();
//        // 获取阴影颜色
//        STHexColor stHexColor = shd.xgetColor();
//        STThemeColor stThemeColor = shd.xgetThemeColor();
//        // 获取填充颜色
//        STHexColor stHexColor1 = shd.xgetFill();
//        STThemeColor stThemeColor1 = shd.xgetThemeFill();
//      }
      String style = xwpfRun.getStyle();
      List<XWPFPicture> embeddedPictures = xwpfRun.getEmbeddedPictures();
      System.out.println();

      if (xwpfRun.getEmbeddedPictures() != null) {
        for (XWPFPicture picture : xwpfRun.getEmbeddedPictures()) {
          String altText = picture.getDescription();
          byte[] data = picture.getPictureData().getData();
          InputStream byteArrayInputStream = new ByteArrayInputStream(data);
          String fileName = picture.getPictureData().getFileName();
          try (FileOutputStream fos = new FileOutputStream("D://pic" + UUID.randomUUID() + ".jpg")) { // 创建
            // FileOutputStream 对象
            fos.write(data); // 将字节数组写入文件
          } catch (IOException e) {
            e.printStackTrace();
          }
          System.out.println(fileName + "[图片：" + altText + "]");
        }
      }
    });
  }

  /**
   * 解析段落样式
   *
   * @param paragraph 段落
   */
  private static ParagraphStyleInfo processParagraph(final XWPFParagraph paragraph) {
    ParagraphStyleInfo paragraphStyleInfo = new ParagraphStyleInfo();

    // 对齐方式
    paragraphStyleInfo.setParagraphAlignment(paragraph.getAlignment());
    // 文本内容
    paragraphStyleInfo.setContent(paragraph.getText());
    List<ParagraphFontStyleInfo> fontStyles = Lists.newArrayList();
    List<XWPFRun> runs = paragraph.getRuns();
    runs.forEach(xwpfRun -> {
      CTRImpl ctr = (CTRImpl) xwpfRun.getCTR();
      Node node = ctr.getDomNode();
      Optional<Node> txtContent = NodeUtil.findNode(node, "txbxContent");
      ParagraphFontStyleInfo fontStyleInfo = new ParagraphFontStyleInfo();
      // 判断是否加粗
      fontStyleInfo.setIsBold(xwpfRun.isBold());
      // 是否设置了倾斜
      fontStyleInfo.setIsItalic(xwpfRun.isItalic());
      // 是否设置了删除线
      fontStyleInfo.setIsStrikeOut(xwpfRun.isStrikeThrough());
      // 字体大小
      fontStyleInfo.setFontSize(xwpfRun.getFontSizeAsDouble());
      // 行间距
      fontStyleInfo.setLineSpacing(xwpfRun.getTextPosition());
      // 高亮
      if (xwpfRun.isHighlighted()) {
        System.out.println(xwpfRun.getTextHightlightColor().toString());
      }
      if (txtContent.isPresent()) {
        fontStyleInfo.setContent(NodeUtil.readNodeValue(txtContent.get()));
      } else {
        CTRPrImpl rPr = (CTRPrImpl) ctr.getRPr();
        // 字体颜色
        fontStyleInfo.setColor(WordColorInfo.getColorInfo(xwpfRun.getColor()));

        // 是否含有下划线
        fontStyleInfo.setUnderline(xwpfRun.getUnderline());

        // 字体
        fontStyleInfo.setFontName(xwpfRun.getFontName());
        // 文本内容
        String content = xwpfRun.getText(-1);
        if (content == null || content.isEmpty()) {
          content = "\t";
        }
        fontStyleInfo.setContent(content);

        // 测试内容
        List<XWPFPicture> embeddedPictures = xwpfRun.getEmbeddedPictures();
        if (embeddedPictures != null) {
          for (XWPFPicture picture : embeddedPictures) {
            byte[] data = picture.getPictureData().getData();
            String fileName = picture.getPictureData().getFileName();
            try (FileOutputStream fos = new FileOutputStream("D://" + fileName)) { // 创建
              // FileOutputStream 对象
              fos.write(data); // 将字节数组写入文件
            } catch (IOException e) {
              e.printStackTrace();
            }
          }
        }
      }
      fontStyles.add(fontStyleInfo);
    });
    paragraphStyleInfo.setFontStyles(fontStyles);
    return paragraphStyleInfo;
  }

  private static TableStyleInfo processTable(final XWPFTable table) {
    TableStyleInfo tableStyleInfo = new TableStyleInfo();
    List<TableRowStyleInfo> list = new ArrayList<>();
    // 处理表格的逻辑
    List<XWPFTableRow> rows = table.getRows();
    Map<String, MergeInfo> mergeMap = new HashMap<>();
    int rowSize = rows.size();
    for (int i = 0; i < rowSize; i++) {
      // 构建行实体
      TableRowStyleInfo tableRowStyleInfo = new TableRowStyleInfo();

      // 获取行
      XWPFTableRow xwpfTableRow = rows.get(i);
      List<TableCellStyleInfo> cellStyle = new ArrayList<>();
      List<XWPFTableCell> tableCells = xwpfTableRow.getTableCells();
      int cellSize = tableCells.size();
      for (int j = 0, realCellMerge = 0; j < cellSize; j++, realCellMerge++) {
        XWPFTableCell xwpfTableCell = tableCells.get(j);
        TableCellStyleInfo tableCellStyleInfo = new TableCellStyleInfo();
        // 背景色
        tableCellStyleInfo.setBackgroundColor(WordColorInfo.getColorInfo(xwpfTableCell.getColor()));
        if (isMergeRow(xwpfTableCell, STMerge.RESTART) || isMergeCell(xwpfTableCell)) {
          // 构建合并实体
          List<MergeInfo> mergeInfos = buildMergeInfo(i, j, realCellMerge, rows);
          mergeMap.putAll(mergeInfos.stream().collect(Collectors.toMap(mergeInfo ->
            mergeInfo.getRowIndex() + "_" + mergeInfo.getCellIndex(), Function.identity())));
          realCellMerge += mergeInfos.stream().filter(mergeInfo -> mergeInfo.getType() == MergeType.MERGE)
            .map(MergeInfo::getMergeCellCount).mapToInt(Integer::intValue).sum();
        }
        tableCellStyleInfo.setCellStyles(xwpfTableCell.getParagraphs().stream().map(WordUtil::processParagraph)
          .collect(Collectors.toList()));
        cellStyle.add(tableCellStyleInfo);
      }
      tableRowStyleInfo.setCells(cellStyle);
      list.add(tableRowStyleInfo);
    }
    tableStyleInfo.setRows(list);
    tableStyleInfo.setMergeMap(mergeMap);
    return tableStyleInfo;
  }

  public static List<MergeInfo> buildMergeInfo(final Integer startRow,
                                               final Integer startCell,
                                               final Integer cellIndex,
                                               final List<XWPFTableRow> rows) {
    int mergeCell = Optional.ofNullable(rows.get(startRow).getCell(startCell)).map(XWPFTableCell::getCTTc).
      map(CTTc::getTcPr).map(CTTcPr::getGridSpan).map(CTDecimalNumber::getVal).map(BigInteger::intValue).orElse(0);

    int mergeRow = 0;
    int maxRow = rows.size();
    boolean run = true;
    for (int i = startRow + 1; i < maxRow; i++) {
      if (!run) {
        break;
      }
      XWPFTableRow xwpfTableRow = rows.get(i);
      int size = xwpfTableRow.getTableCells().size();
      for (int j = 0, realCellIndex = 0; j < size; j++) {
        if (realCellIndex == cellIndex) {
          // 说明下标对上了.
          if (isMergeRow(xwpfTableRow.getCell(j), STMerge.CONTINUE)) {
            // 说明跨行合并?
            mergeRow++;
          } else {
            run = false;
          }
          break;
        }
        // 遍历单元格,获取要合并的列数
        realCellIndex += Optional.ofNullable(rows.get(i).getCell(j)).map(XWPFTableCell::getCTTc).map(CTTc::getTcPr)
          .map(CTTcPr::getGridSpan).map(CTDecimalNumber::getVal).map(BigInteger::intValue).orElse(1);
      }
    }
    if (mergeRow != 0) {
      mergeRow++;
    }
    List<MergeInfo> list = new ArrayList<>();
    list.add(MergeInfo.of(startRow, startCell, MergeType.MERGE, mergeCell, mergeRow));
    if (mergeRow == 0) {
      for (int i = startCell + 1; i <= mergeCell + startCell; i++) {
        list.add(MergeInfo.of(startRow, i, MergeType.CONTINUE, 0, 0));
      }
    } else {
      for (int i = startRow + 1; i <= startRow + mergeRow; i++) {
        list.add(MergeInfo.of(i, startCell, MergeType.CONTINUE, 0, 0));
      }
    }
    return list;
  }

  public static boolean isMerge(final XWPFTableCell cell,
                                final STMerge.Enum mergeType) {
    CTTcImpl ctTc = (CTTcImpl) cell.getCTTc();
    if (ctTc.isSetTcPr()) {
      CTTcPrImpl tcPr = (CTTcPrImpl) ctTc.getTcPr();
      if (tcPr.isSetVMerge()) {
        // 判断是否设置合并行
        CTVMerge vMerge = tcPr.getVMerge();
        if (vMerge != null && mergeType == vMerge.getVal()) {
          return true;
        }
      }
      // 合并列数
      return tcPr.isSetGridSpan();
    }
    return false;
  }

//  private static void createWord() {
//    // 创建文本对象
//    XWPFDocument docxDocument = new XWPFDocument();
//    // 创建段落对象
//    XWPFParagraph p1 = docxDocument.createParagraph();
//    // 对齐方式
//    p1.setAlignment(ParagraphAlignment.LEFT);
//    // 下边框
//    p1.setBorderBetween(Borders.APPLES);
//    p1.setBorderBottom(Borders.APPLES);
//    p1.setBorderLeft(Borders.APPLES);// 指定应显示在左边页面指定段周围的边界。
//    p1.setBorderRight(Borders.ARCHED_SCALLOPS);// 指定应显示在右侧的页面指定段周围的边界。
//    p1.setBorderTop(Borders.ARCHED_SCALLOPS);// 指定应显示上方一组有相同的一组段边界设置的段落的边界。这几个是对段落之间的格式的统一，相当于格式刷
//    p1.setFirstLineIndent(99);//---正文宽度会稍微变窄
//    p1.setFontAlignment(1);//---段落的对齐方式 1左 2中 3右 4往上 左 不可写0和负数
//    p1.setIndentationFirstLine(400);//---首行缩进,指定额外的缩进，应适用于父段的第一行。
//    p1.setIndentationHanging(400);//---首行前进,指定的缩进量，应通过第一行回到开始的文本流的方向上移动缩进从父段的第一行中删除。
//    p1.setIndentationLeft(400);//---整段缩进（右移）指定应为从左到右段，该段的内容的左边的缘和这一段文字左边的距和右边文本边距和左段权中的那段文本的右边缘之间的缩进,如果省略此属性，则应假定其值为零。
//    p1.setIndentationRight(400);//---指定应放置这一段，该段的内容从左到右段的右边缘的正确文本边距和右边文本边距和左段权中的那段文本的右边缘之间的缩进,如果省略此属性，则应假定其值为零。
//    p1.setIndentFromLeft(400);//---整段右移
//    p1.setIndentFromRight(400);
//    p1.setNumID(BigInteger.TEN);
//    p1.setPageBreak(true);//--指定当渲染此分页视图中的文档，这一段的内容都呈现在文档中的新页的开始。
//    p1.setSpacingAfter(6);//--指定应添加在文档中绝对单位这一段的最后一行之后的间距。
//    p1.setSpacingAfterLines(6);//--指定应添加在此线单位在文档中的段落的最后一行之后的间距。
//    p1.setSpacingBefore(6);//--指定应添加上面这一段文档中绝对单位中的第一行的间距。
//    p1.setSpacingBeforeLines(6);//--指定应添加在此线单位在文档中的段落的第一行之前的间距。
//    p1.setSpacingLineRule(LineSpacingRule.AT_LEAST);//--指定行之间的间距如何计算存储在行属性中。
//    p1.setStyles("");//--此方法提供了样式的段落，这非常有用.
//    p1.setVerticalAlignment(TextAlignment.CENTER);//---指定的文本的垂直对齐方式将应用于此段落中的文本
//    p1.setWordWrapped(true);//--此元素指定是否消费者应中断超过一行的文本范围，通过打破这个词 （打破人物等级） 的两行或通过移动到下一行 （在词汇层面上打破） 这个词的拉丁文字。
//  }

  /**
   * @param cell
   * @param mergeType
   * @return
   */
  public static boolean isMergeRow(final XWPFTableCell cell,
                                   final STMerge.Enum mergeType) {
    return Optional.ofNullable(cell).map(XWPFTableCell::getCTTc).map(CTTc::getTcPr)
      .map(CTTcPr::getVMerge).map(CTVMerge::getVal).orElse(null) == mergeType;
  }

  /**
   * 是否合并列
   *
   * @param cell 列
   * @return 是否有合并
   */
  public static boolean isMergeCell(final XWPFTableCell cell) {
    Optional<CTTcPr> ctTcPr = Optional.ofNullable(cell).map(XWPFTableCell::getCTTc).map(CTTc::getTcPr);
    return ctTcPr.map(CTTcPr::getVMerge).map(CTVMerge::getVal).orElse(null) != STMerge.CONTINUE
      && ctTcPr.map(CTTcPr::isSetGridSpan).orElse(false);
  }

  /**
   * 创建段落
   *
   * @param doc      word
   * @param pa       对齐方式
   * @param text     文本内容
   * @param bold     是否加粗
   * @param size     文字大小
   * @param position 行间距(正常文本间距为5，标题间距20)
   */
  private static void selectParagraph(final XWPFDocument doc, final ParagraphAlignment pa, final String text,
                                      final Boolean bold, final Integer size, final Integer position) {
    // 新建一个段落
    XWPFParagraph xwpfParagraph = doc.createParagraph();
    // 创建段落文本
    XWPFRun xwpfRun = xwpfParagraph.createRun();

    //对齐方式
    xwpfParagraph.setAlignment(pa);
    //文本内容
    xwpfRun.setText(text);
    //是否加粗
    xwpfRun.setBold(bold);
    //字体大小
    xwpfRun.setFontSize(size);
    //行间距
    xwpfRun.setTextPosition(position);

  }

  private static void createRun(final XWPFParagraph p1) {
    List<XWPFRun> list = p1.getRuns();
    list.forEach(r1 -> {
      String text = r1.getText(-1);
      // 行间距
      int textPosition = r1.getTextPosition();
      //也是设置删除线，可能有细微的区别吧

      CTR ctr = r1.getCTR();


      r1.setStrikeThrough(true);
      //变的有重影（变黑了一点）
      r1.setEmbossed(true);
      //设置双删除线
      r1.setDoubleStrikethrough(true);
      //---设置字体颜色
      r1.setColor("33CC00");
      r1.setFontFamily("fantasy");
      //---设置ASCII(0 - 127)字体样式
      r1.setFontFamily("cursive");
      //---"加黑加粗"
      r1.setBold(true);
      //---字体大小
      r1.setFontSize(11);
      //---倾斜
      r1.setItalic(true);
      //---改变了  英文字母  的格式
      r1.setSmallCaps(true);
      //---valign垂直对齐的
      r1.setSubscript(VerticalAlign.BASELINE);
      //--填underline type设置下划线
      r1.setUnderline(UnderlinePatterns.DASH);
    });
  }

  //插入图片
//根据我自己的计算，
//代码里传入的width，1大概对应word中图片宽度2.65mm
//代码里传入的height，1大概对应word中图片高度2.64mm
//有需要可以自己算一下，可能会有一点误差，稍微改一下就好了
  private static void createPicture(XWPFDocument doc, String urlVisit, Integer width, Integer height) {
    InputStream in = null;
    try {
      XWPFParagraph firstParagraph = doc.createParagraph();
      XWPFRun run = firstParagraph.createRun();
      // 获取远程图片
      URL url = new URL(urlVisit);
      in = url.openStream();
      //图片输入流、图片类型、图片名称、宽度、高度
      run.addPicture(in, org.apache.poi.xwpf.usermodel.Document.PICTURE_TYPE_PNG, "",
        Units.pixelToEMU(width), Units.pixelToEMU(height));
      //换行
      run.addBreak(BreakType.TEXT_WRAPPING);
    } catch (InvalidFormatException | IOException e) {
      e.printStackTrace();
    }
  }

  //设置行间距 size:固定值大小
  public static void setLineSpace(final XWPFParagraph p, final int size) {
    CTP ctp = p.getCTP();
    CTPPr ppr = ctp.isSetPPr() ? ctp.getPPr() : ctp.addNewPPr();
    CTSpacing spacing = ppr.isSetSpacing() ? ppr.getSpacing() : ppr.addNewSpacing();
    spacing.setAfter(BigInteger.valueOf(0));
    spacing.setBefore(BigInteger.valueOf(0));
    //设置行距类型为 EXACT
    spacing.setLineRule(STLineSpacingRule.EXACT);
    //1磅数是20
    spacing.setLine(BigInteger.valueOf(size * 20));
  }

  /**
   * 设置角标段落普通文字样式
   *
   * @param text       文本
   * @param bold       是否加粗
   * @param size       字体大小
   * @param fontFamily 字体
   */
  private static void createSupText(XWPFRun r, String text, Boolean bold,
                                    Integer size, String fontFamily) {
    r.setText(text);    //文本内容
    r.setBold(bold);    //字体是否加粗
    r.setFontSize(size);    //字体大小
    r.setFontFamily(fontFamily);   //字体
  }

  /**
   * 设置角标段落角标文字样式
   *
   * @param text       文本
   * @param bold       是否加粗
   * @param size       字体大小
   * @param fontFamily 字体
   */
  private static void createSup(final XWPFRun r, final String text, final Boolean bold,
                                final Integer size, final String fontFamily) {
    r.setText(text);    //文本内容
    r.setBold(bold);    //字体是否加粗
    r.setFontSize(size);    //字体大小
    r.setFontFamily(fontFamily);   //字体
    // 添加下标
    CTVerticalAlignRun ctVerticalAlignRun = r.getCTR().addNewRPr().addNewVertAlign();
    // SUPERSCRIPT 上标 SUBSCRIPT 下标
//    ctVerticalAlignRun.setVal(STVerticalAlignRun.SUBSCRIPT);
  }

  public static void main(String[] args) throws IOException {
    String s = readWord("D://大试报告-test1.docx", 1, 1);

//    try {
    String filePath = "D://demo.docx";
//      String filePath = "D://大试报告-test - 副本.docx";
    int startRow = 0; // Specify the starting row to parse
    int endColumn = 10; // Specify the ending column to parse

//    String htmlContent = convertToHtml(filePath, startRow, endColumn);
//    System.out.println(htmlContent);
//    } catch (IOException e) {
//      e.printStackTrace();
//    }


//    FileInputStream fis = new FileInputStream("D://大试报告-test.docx");
//    XWPFDocument document = new XWPFDocument(fis);
//    XWPFStyles styles = document.getStyles();
//    // 按序读取word
//    List<IBodyElement> bodyElements = document.getBodyElements();
//    StringBuilder htmlCode = new StringBuilder();
//    bodyElements.forEach(element -> {
//      if (element instanceof XWPFParagraph) {
//        // 段落
//        XWPFParagraph paragraph = (XWPFParagraph) element;
//        htmlCode.append(convertToHtml(paragraph, "span", ConvertType.WORD_TO_HTML));
//        System.out.println();
//      } else if (element instanceof XWPFTable) {
//        // 表格
//        htmlCode.append(convertToHtml((XWPFTable) element, "span", ConvertType.WORD_TO_HTML));
//        System.out.println();
//      }
//    });
//    System.out.println(htmlCode);
  }

  public static String readWord(String filePath, int startRow, int endColumn) {
    try (FileInputStream fis = new FileInputStream(filePath)) {
      XWPFDocument document = new XWPFDocument(fis);

      Document documentStyle = new Document(document, FileStream::getFileName);
      System.out.println();
      List<IBodyElement> bodyElements = document.getBodyElements();

      List<String> list = Lists.newArrayList();
      for (int i = 0; i < bodyElements.size(); i++) {
        if (bodyElements.get(i) instanceof XWPFParagraph) {
          WordParagraph wordParagraph = new WordParagraph(bodyElements.get(i), i, documentStyle, false);
          list.add(wordParagraph.getLabels().stream().map(CustomLabel::generateHTMLCode)
            .collect(Collectors.joining("")));
          System.out.println();
        }
        System.out.println();
      }
      System.out.println(String.join("", list));

      CTStyles style = document.getStyle();

      List<POIXMLDocumentPart.RelationPart> relationParts = document.getRelationParts();
      relationParts.forEach(relationPart -> {
        PackageRelationship relationship = relationPart.getRelationship();

        POIXMLDocumentPart documentPart = relationPart.getDocumentPart();
        // 样式类型, 字体,主题

        // 不知何用之有
        String relationshipType = relationship.getRelationshipType();


      });

      return null;
    } catch (Exception e) {
      log.error("解析word失败: {}", e.getMessage(), e);
      return null;
    }
  }

  //
//  /**
//   * 从段落最外层获取段落的对齐、做缩进、右缩进、首行缩进、段前、段后、行间距、间距规则；字体信息
//   *
//   * @param p
//   * @param ficesStyleDTO
//   * @return
//   */
//  public static FicesStyleDTO getParagraphStyle(final XWPFParagraph p, FicesStyleDTO ficesStyleDTO) {
//
//
//    ParagraphAlignment alignment = p.getAlignment();
//    if (null != alignment && alignment.getValue() != -1 && null == ficesStyleDTO.getAlignMent()) {
//      // 居中
//      ficesStyleDTO.setAlignMent(alignment.name().toLowerCase());
//    }
//
//    int indentationLeftChars = p.getIndentationLeftChars();
//    if (indentationLeftChars != -1 && null == ficesStyleDTO.getLeftChars()) {
//      double leftChars = (double) indentationLeftChars / 100;
//      ficesStyleDTO.setLeftChars(String.valueOf(leftChars));
//    }
//    int indentationRightChars = p.getIndentationRightChars();
//    if (indentationRightChars != -1 && null == ficesStyleDTO.getRightChars()) {
//      double rightChars = (double) indentationRightChars / 100;
//      ficesStyleDTO.setRightChars(String.valueOf(rightChars));
//    }
//
//
//    int spacingAfterLines = p.getSpacingAfterLines();
//    if (spacingAfterLines != -1 && null == ficesStyleDTO.getAfterLines()) {
//      double afterLines = (double) spacingAfterLines / 100;
//      ficesStyleDTO.setAfterLines(String.valueOf(afterLines));
//    }
//    int spacingBeforeLines = p.getSpacingBeforeLines();
//    if (spacingBeforeLines != -1 && null == ficesStyleDTO.getBeforeLines()) {
//      double beforeLines = (double) spacingBeforeLines / 100;
//      ficesStyleDTO.setBeforeLines(String.valueOf(beforeLines));
//    }
//
//    double spacingBetween = p.getSpacingBetween();
//    if (spacingBetween != -1 && null == ficesStyleDTO.getSpaceBetween()) {
//      ficesStyleDTO.setSpaceBetween(String.valueOf(spacingBetween));
//    }
//    LineSpacingRule spacingLineRule = p.getSpacingLineRule();
//    if (null != spacingLineRule && null == ficesStyleDTO.getSpacingLineRule()) {
//
//      ficesStyleDTO.setSpacingLineRule(spacingLineRule.name());
//    }
//
////具体属性style
//    List<XWPFRun> runs = p.getRuns();
//    for (int i = 0; i < runs.size(); i++) {
//      XWPFRun xwpfRun = runs.get(i);
//      if (null != xwpfRun.text() && xwpfRun.text().length() > 2) {
//        getFontStyle(xwpfRun, ficesStyleDTO);
//        break;
//      }
//    }
//    return ficesStyleDTO;
//  }
//
//  /**
//   * 获取段落中的 ppr的信息
//   *
//   * @param ctpPr         document.xml 的ppr的数据
//   * @param styles        document的所有style列表
//   * @param ficesStyleDTO 结果报错的变量
//   * @return
//   */
//  public static FicesStyleDTO getParagraphStyle(CTPPr ctpPr, XWPFStyles styles, FicesStyleDTO ficesStyleDTO) {
//
//    if (null == ctpPr) {
//      return ficesStyleDTO;
//    }
//    if (ctpPr.isSetOutlineLvl() && null == ficesStyleDTO.getStyleLevel()) {
//      ficesStyleDTO.setStyleLevel(ctpPr.getOutlineLvl().getVal().toString());
//    }
//
//
//    if (ctpPr.isSetJc() && null == ficesStyleDTO.getAlignMent()) {
//      ficesStyleDTO.setAlignMent(ctpPr.getJc().getVal().toString());
//    }
//    CTInd ind = ctpPr.getInd();
//    if (null != ind) {
//
//
//      if (ind.isSetLeftChars() && null == ficesStyleDTO.getLeftChars()) {
//        BigInteger leftChars = ind.getLeftChars();
//        double leftChar = leftChars.doubleValue() / 100;
//        ficesStyleDTO.setLeftChars(String.valueOf(leftChar));
//      }
//
//      if (ind.isSetRightChars() && null == ficesStyleDTO.getRightChars()) {
//        BigInteger rightChars = ind.getLeftChars();
//        double rightChar = rightChars.doubleValue() / 100;
//        ficesStyleDTO.setRightChars(String.valueOf(rightChar));
//      }
//
//      if (ind.isSetFirstLineChars() && null == ficesStyleDTO.getFirstChars()) {
//        BigInteger firstLineChars = ind.getFirstLineChars();
//        double firstLineChar = firstLineChars.doubleValue() / 100;
//        ficesStyleDTO.setFirstChars(String.valueOf(firstLineChar));
//      }
//    }
//    CTSpacing spacing = ctpPr.getSpacing();
//    if (null != spacing) {
//
//      if (spacing.isSetBeforeLines() && null == ficesStyleDTO.getBeforeLines()) {
//        BigInteger beforeLines = spacing.getBeforeLines();
//        double beforeline = beforeLines.doubleValue() / 100.0;
//        ficesStyleDTO.setBeforeLines(String.valueOf(beforeline));
//      }
//
//      if (spacing.isSetAfterLines() && null == ficesStyleDTO.getAfterLines()) {
//        BigInteger afterLines = spacing.getAfterLines();
//        double afterline = afterLines.doubleValue() / 100.0;
//        ficesStyleDTO.setAfterLines(String.valueOf(afterline));
//      }
//
//
//      if (spacing.isSetLine() && null == ficesStyleDTO.getSpaceBetween()) {
//
//        double twips = Units.toDXA(POIXMLUnits.parseLength(spacing.xgetLine()));
//        double lines = (twips / (double) (spacing.getLineRule() != null && spacing.getLineRule() != STLineSpacingRule.AUTO ? 20 : 240));
//        ficesStyleDTO.setSpaceBetween(String.valueOf(lines));
//      }
//
//      if (spacing.isSetLineRule() && null == ficesStyleDTO.getSpacingLineRule()) {
//        LineSpacingRule spacingRule = LineSpacingRule.valueOf(spacing.getLineRule().intValue());
//        ficesStyleDTO.setSpacingLineRule(spacingRule.name());
//      }
//    }
//    CTParaRPr rPr = ctpPr.getRPr();
//    if (null != rPr) {
//      getFontStyle(rPr, ficesStyleDTO);
//    }
////获取对应的样式数据
//    CTString pStyle = ctpPr.getPStyle();
//    if (null != pStyle) {
//
//      getParagraphStyleIdStyle(pStyle.getVal(), styles, ficesStyleDTO);
//    }
//
//
//    return ficesStyleDTO;
//
//  }
//
//  /**
//   * 获取pstyleId 下的 ppr的数据
//   *
//   * @param pPr           style列表下的ppr数据
//   * @param ficesStyleDTO 结果报错的变量
//   * @return
//   */
//  public static FicesStyleDTO getParagraphStyle(final CTPPr pPr, FicesStyleDTO ficesStyleDTO) {
//    if (null == pPr) {
//      return ficesStyleDTO;
//    }
//    if (pPr.isSetOutlineLvl() && null == ficesStyleDTO.getStyleLevel()) {
//      ficesStyleDTO.setStyleLevel(pPr.getOutlineLvl().getVal().toString());
//    }
//
//
//    if (pPr.isSetJc() && null == ficesStyleDTO.getAlignMent()) {
//      ficesStyleDTO.setAlignMent(pPr.getJc().getVal().toString());
//    }
//    CTInd ind = pPr.getInd();
//    if (null != ind) {
//      if (ind.isSetLeftChars() && null == ficesStyleDTO.getLeftChars()) {
//        BigInteger leftChars = ind.getLeftChars();
//        double leftChar = leftChars.doubleValue() / 100;
//        ficesStyleDTO.setLeftChars(String.valueOf(leftChar));
//      }
//
//      if (ind.isSetRightChars() && null == ficesStyleDTO.getRightChars()) {
//        BigInteger rightChars = ind.getLeftChars();
//        double rightChar = rightChars.doubleValue() / 100;
//        ficesStyleDTO.setRightChars(String.valueOf(rightChar));
//      }
//
//      if (ind.isSetFirstLineChars() && null == ficesStyleDTO.getFirstChars()) {
//        BigInteger firstLineChars = ind.getFirstLineChars();
//        double firstLineChar = firstLineChars.doubleValue() / 100;
//        ficesStyleDTO.setFirstChars(String.valueOf(firstLineChar));
//      }
//    }
//    CTSpacing spacing = pPr.getSpacing();
//    if (null != spacing) {
//
//      if (spacing.isSetBeforeLines() && null == ficesStyleDTO.getBeforeLines()) {
//        BigInteger beforeLines = spacing.getBeforeLines();
//        double beforeline = beforeLines.doubleValue() / 100.0;
//        ficesStyleDTO.setBeforeLines(String.valueOf(beforeline));
//      }
//
//      if (spacing.isSetAfterLines() && null == ficesStyleDTO.getAfterLines()) {
//        BigInteger afterLines = spacing.getAfterLines();
//        double afterline = afterLines.doubleValue() / 100.0;
//        ficesStyleDTO.setAfterLines(String.valueOf(afterline));
//      }
//
//
//      if (spacing.isSetLine() && null == ficesStyleDTO.getSpaceBetween()) {
//
//        double twips = Units.toDXA(POIXMLUnits.parseLength(spacing.xgetLine()));
//        double lines = (twips / (double) (spacing.getLineRule() != null && spacing.getLineRule() != STLineSpacingRule.AUTO ? 20 : 240));
//        ficesStyleDTO.setSpaceBetween(String.valueOf(lines));
//      }
//
//      if (spacing.isSetLineRule() && null == ficesStyleDTO.getSpacingLineRule()) {
//        LineSpacingRule spacingRule = LineSpacingRule.valueOf(spacing.getLineRule().intValue());
//        ficesStyleDTO.setSpacingLineRule(spacingRule.name());
//      }
//    }
//
//    pPr.getPStyle();
//
//
//    pPr.getKeepLines();
//    return ficesStyleDTO;
//
//
//  }
//
//  /**
//   * document.xml 下的段落ppr 下的 rpr的信息获取字体信息
//   *
//   * @param rPr           document.xml 下的段落ppr 下的 rpr的信息
//   * @param ficesStyleDTO
//   * @return
//   */
//  public static FicesStyleDTO getFontStyle(CTParaRPr rPr, FicesStyleDTO ficesStyleDTO) {
//    List<CTFonts> rFontsList = rPr.getRFontsList();
//    if (rFontsList != null && rFontsList.size() > 0) {
//      CTFonts ctFonts = rFontsList.get(0);
//      String eastAsia = ctFonts.getEastAsia();
//      if (null != eastAsia && null == ficesStyleDTO.getFontNameEastasia()) {
//        ficesStyleDTO.setFontNameEastasia(eastAsia);
//      }
//      String ascii = ctFonts.getAscii();
//      if (null != ascii && null == ficesStyleDTO.getFontNameAscii()) {
//        ficesStyleDTO.setFontNameAscii(ascii);
//      }
//      String cs = ctFonts.getCs();
//      if (null != cs && null == ficesStyleDTO.getFontNameCs()) {
//        ficesStyleDTO.setFontNameCs(cs);
//      }
//
//      String hAnsi = ctFonts.getHAnsi();
//      if (null != hAnsi && null == ficesStyleDTO.getFontNameHansi()) {
//        ficesStyleDTO.setFontNameHansi(hAnsi);
//      }
//
//      STHint.Enum hint = ctFonts.getHint();
//
//
//    }
//    List<CTHpsMeasure> szList = rPr.getSzList();
//    if (szList != null && szList.size() > 0) {
//      CTHpsMeasure ctHpsMeasure = szList.get(0);
//      Object val = ctHpsMeasure.getVal();
//      if (null == ficesStyleDTO.getFontSize()) {
//        ficesStyleDTO.setFontSize(val.toString());
//      }
//    }
//    List<CTOnOff> bList = rPr.getBList();
//    if (bList != null && bList.size() > 0) {
//      CTOnOff ctOnOff = bList.get(0);
//      if (null == ficesStyleDTO.getIsBlod()) {
//        ficesStyleDTO.setIsBlod("true");
//      }
//    }
//    List<CTColor> colorList = rPr.getColorList();
//    if (colorList != null && colorList.size() > 0) {
//      CTColor ctColor = colorList.get(0);
//      if (null == ficesStyleDTO.getFontColor()) {
//        ficesStyleDTO.setFontColor(ctColor.getVal().toString());
//      }
//    }
//    return ficesStyleDTO;
//  }
//
//  /**
//   * document.xml 下的段落rpr 信息获取字体信息
//   *
//   * @param rPr
//   * @param ficesStyleDTO
//   * @return
//   */
//  public static FicesStyleDTO getFontStyle(CTRPr rPr, FicesStyleDTO ficesStyleDTO) {
//    List<CTFonts> rFontsList = rPr.getRFontsList();
//    if (rFontsList != null && rFontsList.size() > 0) {
//      CTFonts ctFonts = rFontsList.get(0);
//      String eastAsia = ctFonts.getEastAsia();
//      if (null != eastAsia && null == ficesStyleDTO.getFontNameEastasia()) {
//        ficesStyleDTO.setFontNameEastasia(eastAsia);
//      }
//      String ascii = ctFonts.getAscii();
//      if (null != ascii && null == ficesStyleDTO.getFontNameAscii()) {
//        ficesStyleDTO.setFontNameAscii(ascii);
//      }
//      String cs = ctFonts.getCs();
//      if (null != cs && null == ficesStyleDTO.getFontNameCs()) {
//        ficesStyleDTO.setFontNameCs(cs);
//      }
//
//      String hAnsi = ctFonts.getHAnsi();
//      if (null != hAnsi && null == ficesStyleDTO.getFontNameHansi()) {
//        ficesStyleDTO.setFontNameHansi(hAnsi);
//      }
//
//      STHint.Enum hint = ctFonts.getHint();
//
//
//    }
//    List<CTHpsMeasure> szList = rPr.getSzList();
//    if (szList != null && szList.size() > 0) {
//      CTHpsMeasure ctHpsMeasure = szList.get(0);
//      Object val = ctHpsMeasure.getVal();
//      if (null == ficesStyleDTO.getFontSize()) {
//        ficesStyleDTO.setFontSize(val.toString());
//      }
//    }
//    List<CTOnOff> bList = rPr.getBList();
//    if (bList != null && bList.size() > 0) {
//      CTOnOff ctOnOff = bList.get(0);
//      if (null != ctOnOff && null == ficesStyleDTO.getIsBlod()) {
//        Object val = ctOnOff.getVal();
//
//        ficesStyleDTO.setIsBlod("true");
//      }
//    }
//    List<CTColor> colorList = rPr.getColorList();
//    if (colorList != null && colorList.size() > 0) {
//      CTColor ctColor = colorList.get(0);
//      if (null == ficesStyleDTO.getFontColor()) {
//        ficesStyleDTO.setFontColor(ctColor.getVal().toString());
//      }
//    }
//    return ficesStyleDTO;
//  }
//
//  /***
//   * 获取document.xml的 run下获取字体数据
//   * @param xwpfRun document.xml的 run下获取字体数据
//   * @param ficesStyleDTO
//   * @return
//   */
//  public static FicesStyleDTO getFontStyle(final XWPFRun xwpfRun, FicesStyleDTO ficesStyleDTO) {
//    String fontName = xwpfRun.getFontName();
//    if (null != fontName && !"".equals(fontName) && null == ficesStyleDTO.getFontName()) {
//      ficesStyleDTO.setFontName(fontName);
//    }
//    Double fontSizeAsDouble = xwpfRun.getFontSize();
//    if (null != fontSizeAsDouble && null == ficesStyleDTO.getFontSize()) {
//      ficesStyleDTO.setFontSize(fontSizeAsDouble.toString());
//    }
//
//    String color = xwpfRun.getColor();
//    if (null != color && null == ficesStyleDTO.getFontColor()) {
//      ficesStyleDTO.setFontColor(color);
//    }
//    CTR ctr = xwpfRun.getCTR();
//    if (null != ctr) {
//      CTRPr rPr = ctr.getRPr();
//      if (null != rPr) {
//        getFontStyle(rPr, ficesStyleDTO);
//      }
//    }
//    return ficesStyleDTO;
//  }
//
//
//  /**
//   * 根据pstyleId 获取对应的对应的style信息，从而获取对应的段落和字体信息
//   *
//   * @param pstyle
//   * @param styles
//   * @param ficesStyleDTO
//   * @return
//   */
//  public static FicesStyleDTO getParagraphStyleIdStyle(String pstyle, XWPFStyles styles, FicesStyleDTO ficesStyleDTO) {
//    XWPFStyle styles = styles.getStyles(pstyle);
//    CTStyle ctStyle = styles.getCTStyle();
//
//    CTPPr pPr = ctStyle.getPPr();
//    if (null != pPr) {
//      getParagraphStyle(pPr, ficesStyleDTO);
//    }
//
//
//    CTRPr rPr = ctStyle.getRPr();
//    if (null != rPr) {
//      getFontStyle(rPr, ficesStyleDTO);
//    }
//
//    CTString basedOn = ctStyle.getBasedOn();
//    if (null != basedOn) {
//      getParagraphStyleIdStyle(basedOn.getVal(), styles, ficesStyleDTO);
//    }
//    return ficesStyleDTO;
//
//
//  }
//  public static String convertToHtml(String filePath, int startRow, int endColumn) throws IOException {
//    try (FileInputStream fis = new FileInputStream(filePath)) {
//      XWPFDocument document = new XWPFDocument(fis);
//
//      // Configure options for HTML conversion
//      XHTMLOptions options = XHTMLOptions.create();
//      options.setIgnoreStylesIfUnused(false); // Parse styles
//      options.setFragment(true); // Produce HTML fragment only (no <html>, <body> tags)
//
//      // Convert document to XHTML
//      ByteArrayOutputStream out = new ByteArrayOutputStream();
//      XHTMLConverter.getInstance().convert(document, out, options);
//      String htmlContent = out.toString();
//
//      return htmlContent;
//    }
//  }
//
//  public static String convertToWord(String filePath, int startRow, int endColumn) throws IOException {
//    try (FileInputStream fis = new FileInputStream(filePath)) {
//      XWPFDocument document = new XWPFDocument(fis);
//
//      // Configure options for HTML conversion
//      XHTMLOptions options = XHTMLOptions.create();
//      options.setIgnoreStylesIfUnused(false); // Parse styles
//      options.setFragment(true); // Produce HTML fragment only (no <html>, <body> tags)
//
//      // Convert document to XHTML
//      ByteArrayOutputStream out = new ByteArrayOutputStream();
//      XHTMLConverter.getInstance().convert(document, out, options);
//      String htmlContent = out.toString();
//
//      return htmlContent;
//    }
//  }

  /**
   * 跨列合并
   *
   * @param table    表格
   * @param row      所合并的行
   * @param fromCell 起始列
   * @param toCell   终止列
   */
  public void mergeCellsHorizontal(XWPFTable table, int row, int fromCell, int toCell) {
    for (int cellIndex = fromCell; cellIndex <= toCell; cellIndex++) {
      XWPFTableCell cell = table.getRow(row).getCell(cellIndex);
      if (cellIndex == fromCell) {
        cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
      } else {
        cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
      }
    }
  }

  /**
   * 跨行合并
   *
   * @param table   表格
   * @param col     所合并的列
   * @param fromRow 起始行
   * @param toRow   终止行
   */
  public void mergeCellsVertically(XWPFTable table, int col, int fromRow, int toRow) {
    for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {
      XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
      if (rowIndex == fromRow) {
        cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
      } else {
        cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
      }
    }
  }

}
